<template>
  <div class="home">
    <!-- VR-Area -->
    <div id="left" class="left">
      <VR :disabled="drawer" ref="vr"></VR>
    </div>
    <!-- Adjust-Area -->
    <div class="right">
      <!-- Camera-Area -->
      <!-- local -->
      <div class="videoWrapper">
        <video id="video1" class="video" autoplay muted></video>
      </div>
      <!-- remote -->
      <div class="videoWrapper">
        <video id="video2" class="video" autoplay></video>
      </div>
      <!-- buttons -->
      <div class="btnArea flex flex-column justify-center items-center">
        <div class="w-100 flex flex-row justify-center items-center mb-1">
          <el-tag class="mr-05">ID：{{ localId }}</el-tag>
          <el-button type="primary" style="cursor:pointer" @click="onCopy()">复制</el-button>
          <el-button type="primary" style="cursor:pointer" @click="test()">test</el-button>
        </div>
        <el-button
          type="primary"
          class="w-90"
          @click="isVideoOn === true ? closeDevice() : creatorRTC()"
        >{{ isVideoOn === true ? `关闭视频` : `打开视频` }}</el-button>
      </div>
    </div>

    <!-- 抽屉: 询问发起/加入场景 -->
    <el-drawer
      title="多人体感协作实现"
      v-model:modelValue="drawer"
      :before-close="handleDrawerClose"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      size="25%"
    >
      <div style="height: 95%" class="flex flex-column justify-end">
        <div class="id-input flex flex-column justify-center items-center">
          <el-input placeholder="Please enter the other party's id" v-model="toUser"></el-input>
          <el-button class="start-btn" type="primary" @click="link2RTC()">加入场景</el-button>
          <el-button class="start-btn" type="primary" @click="drawer = false">创建场景</el-button>
        </div>
        <div class="flex flex-row justify-center items-center">
          <el-tag class="mr-05">ID：{{ localId }}</el-tag>
          <el-button type="primary" style="cursor:pointer" @click="onCopy()">复制</el-button>
        </div>
      </div>
    </el-drawer>
  </div>
</template>

<script>
const { startWS } = require("../api/socket")
import { tVariantSetTimeout } from '../util/util'
import VR from '../components/vr/vr.vue'
import { initHandWorks, closeHandWorks } from '../components/mediapipe/mediapipe'
export default {
  components: {
    VR
  },
  data() {
    return {
      websocket: null,
      toUser: '',
      content: ``,
      modeRTC: false,
      characterRTC: 'receiver',
      // 是否打开视频
      isVideoOn: false,
      // 本地websocket id
      localId: `-`,
      // RTC对象
      rtc: null,
      // 初始窗口
      drawer: true,
    }
  },
  mounted() {
    this.startWS();
    // console.log(`flvjs: ${JSON.stringify(flvjs)}`);
  },
  methods: {
    sent() {
      if (this.characterRTC === `receiver`) {
        this.rtc.dataChannel.send(this.content)
      }
      else {
        this.rtc.dataChannel.send(this.content)
      }
    },
    startWS() {
      startWS().then((res) => {
        if (res.status === 200 || res.status === 304) this.connectWebSocket();
        else console.warn("ws start error");
      });
    },
    /**
     * @todu websocket 初始化
     * @param { WebSocket对象 } websocket
     */
    connectWebSocket() {
      // 判断当前浏览器是否支持WebSocket
      if ("WebSocket" in window) {
        this.websocket = new WebSocket(
          // "ws://39.99.129.23:5273"
          "ws://127.0.0.1:5273"
        );
      }
      // 连接发生错误的回调方法
      this.websocket.onerror = function (event) {
        console.log(event)
      };
      // 连接成功建立的回调方法
      this.websocket.onopen = function (event) {
      };
      // 接收到消息的回调方法
      // 刚启动程序时便会直接与服务端WebSocket连接, 获取客户端自身的localId
      this.websocket.onmessage = (event) => {
        if (this.modeRTC === true) {
          // 进行RTC通信
          let paper = JSON.parse(event.data)
          if (this.characterRTC === `receiver`) {
            this.receiverRTC();
            if (paper.type === 'offer' && paper.sdp) this.rtc.setRemoteDescription(paper.sdp)
            else {
              this.$message({
                showClose: false,
                type: `error`,
                message: '此ID不存在'
              });
            }
            // 获取Answer时会更新SDP, 触发onicecandidate
            this.rtc.createAnswer().then(answer => {
              if (answer !== null) {
                this.rtc.setLocalDescription(answer)
                // 关闭初始抽屉
                this.drawer = false;
              }
            }).then(e => console.log(`Answer Created !`))
          } else {
            if (paper.type === 'answer') return this.rtc.setRemoteDescription(paper.sdp)
            if (paper.type === 'close') return this.rtc.close();
            else console.warn(`get wrong RTC type: got ${paper.type}`)
          }
        } else {
          // 获取客户端id
          this.localId = event.data;
          this.modeRTC = true;
        };
      };
      //连接关闭的回调方法
      this.websocket.onclose = function (event) {
      };
      //监听窗口关闭事件
      window.onbeforeunload = () => {
        // 关闭rtc连接时会将所有连接的通道都断开
        // 如果是加入方, 需通知signaling让对方close此次连接
        if (this.characterRTC === `receiver`) this.websocket.send(JSON.stringify({ type: "close", id: this.toUser }))
        this.rtc.close();
        // 关闭此次websocket连接, RTC连接
        this.websocket.close();
        this.closeDevice();
        this.modeRTC = false;
        // 释放动画的所有内存
        animationMixer.uncacheRoot(animationMixer.getRoot())
        // 释放手势识别中的定时器任务
        closeHandWorks();
      };
    },
    closeWS() {
      // 关闭websocket连接
      this.websocket.close();
      this.websocket = null;
    },

    /**
     * WebRTC 创建方函数
     */
    async creatorRTC() {
      this.characterRTC = `creator`;
      // 初始化RTC对象
      this.rtc = new RTCPeerConnection();
      /**
       * 发起会话: 建立数据通道
       */
      await this.openDevice("video1")
      this.rtc.dataChannel = this.rtc.createDataChannel("channel");
      this.rtc.dataChannel.onopen = e => console.log("Connection Open!");
      this.rtc.dataChannel.onclose = e => console.log("Connection Close!");
      this.rtc.dataChannel.onmessage = e => console.log(`New data: ${e.data}`);
      window.localStream.getTracks().forEach(track => this.rtc.addTrack(track, window.localStream))

      // 在ICE候选得到最优选的过程中打印SDP, 即ICE节点变化的回调
      this.rtc.onicecandidate = e => {
        // 将SDP和要连接的对方的id发给signaling
        tVariantSetTimeout(() => {
          if (this.websocket) this.websocket.send(JSON.stringify({ type: "offer", sdp: this.rtc.localDescription }));
          else console.warn(`Websocket is not established`);
          console.log(`Creator, SDP: ${JSON.stringify(this.rtc.localDescription)}`);
        }, 200);
      }
      // 创建一个用于offer的SDP对象, 会更新SDP, 触发onicecandidate
      if (this.characterRTC === `creator`) {
        this.rtc.createOffer().then(offer => this.rtc.setLocalDescription(offer)).then(a => console.log(`SDP set successfully!`))
        // 关闭初始抽屉
        this.isVideoOn = true;
        // this.drawer = false;
      }
    },

    /**
     * WebRTC 加入方函数
     */
    receiverRTC() {
      // 初始化RTC对象
      this.rtc = new RTCPeerConnection();
      // 在ICE候选得到最优选的过程中打印SDP, 即ICE节点变化的回调
      this.rtc.onicecandidate = e => {
        tVariantSetTimeout(() => {
          // 将SDP(Answer)和要连接的对方的id发给signaling
          if (this.websocket) this.websocket.send(JSON.stringify({ type: 'answer', id: this.toUser, sdp: this.rtc.localDescription }));
          else console.warn(`Websocket is not established`);
          console.log(`Receiver, SDP: ${JSON.stringify(this.rtc.localDescription)}`);
        }, 200);
      }
      /**
       * 接受会话
       */
      this.rtc.ondatachannel = e => {
        this.rtc.dataChannel = e.channel;
        this.rtc.dataChannel.onopen = e => console.log(`Connection Open!`);
        this.rtc.dataChannel.onclose = e => console.log("Connection Close!");
        this.rtc.dataChannel.onmessage = e => console.log(`New message: ${e.data}`);
      }
      this.rtc.ontrack = e => {
        let video = document.getElementById("video2");
        if (video.srcObject !== e.streams[0]) {
          video.style.display = 'block'
          video.srcObject = e.streams[0];
          console.log('Received remote stream');
        }
      }
    },

    /**
     * 摄像头
     */
    openDevice(device) {
      return navigator.mediaDevices.getUserMedia({
        audio: true,
        video: true
      }).then(stream => {
        const video = document.getElementById(device);
        video.srcObject = stream;
        video.style.display = 'block';
        window.localStream = stream;
        // 手势识别任务
        initHandWorks(video, VR.methods.hands_acitons);
      }).catch(e => console.log('getUserMedia() error: ', e));
    },
    closeDevice() {
      window.localStream.getTracks().forEach(track => {
        track.stop();
      });
      this.isVideoOn = false;
      // 关闭rtc连接时会将所有连接的通道都断开
      this.rtc.close();
      // 释放手势识别中的定时器任务
      closeHandWorks();
    },
    /**
     * 剪切板复制回调
     */
    onCopy() {
      this.$copyText(this.localId).then((res) => {
        this.$message({
          showClose: true,
          message: 'Copy successful!'
        });
      })
    },
    handleDrawerClose() {
      this.$confirm('Are you sure you want to quit the program?')
        .then(_ => {
          this.$message({
            showClose: false,
            type: `success`,
            message: 'Welcome next time'
          });
          setTimeout(() => {
            // quit the program
            window.location.href = "about:blank";
            window.close();
          }, 1000);
        })
        .catch(_ => {
        });
    },
    // 连接到对应userId的RTC连接
    link2RTC() {
      if (this.websocket) {
        this.websocket.send(JSON.stringify({ type: "id", id: this.toUser }));
        this.characterRTC = 'receiver'
      }
    },
    test() {
      this.$router.push('test');
    }
  }
}
</script>
<style lang="scss">
.home {
  display: flex;
  flex-direction: row;
  align-items: center;
  padding: 8px;
  background: rgba(196, 196, 196, 0.5);
  position: relative;
}
.left {
  width: 76vw;
  height: calc(100vh - 16px);
  margin-right: 8px;
  border-radius: 6px;
  position: relative;
}
.right {
  width: calc(24vw - 24px);
  height: calc(100vh - 16px);
  border-radius: 6px;
  position: relative;
  .videoWrapper {
    position: relative;
    background: black;
    width: calc(24vw - 24px);
    height: calc(40vh - 8px);
    margin-bottom: 8px;
    border-radius: 6px;
    box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.6);
    .video {
      object-fit: cover;
      width: calc(24vw - 3vh);
      height: calc(40vh - 8px);
      border-radius: 6px;
    }
  }
  .btnArea {
    position: relative;
    width: calc(24vw - 3vh);
    height: calc(20vh - 16px);
    border-radius: 6px;
    border: none;
    overflow: auto;
    box-shadow: 0px 0px 15px rgba(102, 102, 102, 0.4);
  }
}

.communicate {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}

.id-input {
  height: 100%;
  width: 80%;
  margin: 0 auto;
}
.start-btn {
  width: 100%;
  margin: 10px 10px 0px 10px !important;
}

.el-button {
  line-height: 0.4 !important;
  min-height: 0px !important;
}
.el-drawer__header {
  font-weight: bold;
}
</style>
